package org.cobaya.pages;

import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import org.apache.commons.cli.BasicParser;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
import org.apache.commons.io.FileUtils;
import org.cobaya.commons.Collect;
import org.cobaya.commons.IO;
import org.cobaya.commons.Props;

import com.alibaba.fastjson.JSONArray;

public class Main {

	private static final String CMD_BUILD = "b";
	private static final String CMD_REMOVE = "r";
	private static final String CMD_POST = "p";

	private static final String CMD_LINK = "l";
	private static final String CMD_TITLE = "t";

	private static final String META_PROPERTIES = "userdir:/meta.properties";

	private static void _build() {
		try {
			String userDir = IO.PREFIX_USERDIR;
			File _index = IO.openFile(userDir + Props.getProperties(META_PROPERTIES, "site_index"));
			File _404 = IO.openFile(userDir + Props.getProperties(META_PROPERTIES, "site_404"));
			Properties _props = Props.openProperties(META_PROPERTIES);

			List<Note> notes = readNotes();

			for (Note note : notes) {
				File src = IO.openFile(IO.USER_DIR + "/" + note.getFile());
				File output = IO.openFile(IO.USER_DIR + "/" + note.getLink() + ".src");
				GithubPages.markdown(src, output);
				String markdown_src = FileUtils.readFileToString(output, IO.UTF_8);
				Map<Object, Object> props = Collect.map(_props, "site_main", markdown_src);
				GithubPages.freemarker("main.ftl", IO.openFile(IO.USER_DIR + "/" + note.getLink()),
						Collect.map(props, "_post", true));
			}
			tip("all articles rebuiled.");

			GithubPages.freemarker("main.ftl", _index, Collect.map(_props, "notes", notes));
			tip("index.html rebuiled.");

			GithubPages.freemarker("main.ftl", _404, Collect.map(_props, "_404", true));
			tip("404.html rebuiled.");

		} catch (Exception e) {
			e.printStackTrace();
			tip(e.getLocalizedMessage());
		}
	}

	private static void _cmd(String[] args) {
		try {
			CommandLine cmd = parseCmd(args);
			if (cmd.hasOption(CMD_POST)) {
				if (!cmd.hasOption(CMD_TITLE)) {
					tip("-t is required");
					return;
				}
				if (!cmd.hasOption(CMD_LINK)) {
					tip("-l is required");
					return;
				}
				_post(cmd.getOptionValue(CMD_TITLE), cmd.getOptionValue(CMD_LINK));
				return;
			}
			if (cmd.hasOption(CMD_REMOVE)) {
				if (!cmd.hasOption(CMD_TITLE)) {
					tip("-t is required");
					return;
				}
				_remove(cmd.getOptionValue(CMD_TITLE));
				return;
			}
			if (cmd.hasOption(CMD_BUILD)) {
				_build();
				return;
			}
			tip("invalid cmd, do nothing.");
		} catch (Exception e) {
			e.printStackTrace();
			tip(e.getLocalizedMessage());
		}
	}

	private static void _post(String title, String link) {
		if (title == null || title.trim().length() == 0) {
			tip("title must not be blank");
			return;
		}
		if (link == null || link.trim().length() == 0) {
			tip("link must not be blank");
			return;
		}
		try {
			Note note = new Note();
			note.setAuthor(Props.getProperties(META_PROPERTIES, "site_author"));
			note.setDate(getCurrentDate());
			note.setFile(getCurrentPath(link + ".md", false));
			note.setLink(getCurrentPath(link + ".html", false));
			note.setTitle(title);

			List<Note> notes = readNotes();
			checkExists(notes, note);
			notes.add(0, note);
			writeNotes(notes);

			File post = IO.openFile(getCurrentPath(link + ".md", true));
			FileUtils.write(post, "# " + title, IO.UTF_8);
		} catch (Exception e) {
			e.printStackTrace();
			tip(e.getLocalizedMessage());
		}
	}

	private static void _remove(String title) {
		try {
			if (title == null || title.trim().length() == 0) {
				tip("title is blank, do nothing");
				return;
			}

			List<Note> notes = readNotes();
			Note exist = null;
			for (Note note : notes) {
				if (title.equalsIgnoreCase(note.getTitle())) {
					exist = note;
					break;
				}
			}
			if (exist == null) {
				tip("title not found, do nothing");
				return;
			}

			tip("find a article and remove it");
			IO.deleteFile(IO.USER_DIR + "/" + exist.getLink());
			IO.deleteFile(IO.USER_DIR + "/" + exist.getFile());
			notes.remove(exist);
			writeNotes(notes);
		} catch (Exception e) {
			e.printStackTrace();
			tip(e.getLocalizedMessage());
		}
		tip("rebuild now...");
		_build();
	}

	private static void checkExists(List<Note> notes, Note note) throws IOException {
		String link = IO.USER_DIR + "/" + note.getLink();
		File post = IO.openFile(link);
		if (post.exists()) {
			throw new IOException("[" + link + "] exists, please change");
		}
		for (Note exists : notes) {
			if (exists.getTitle().equals(note.getTitle())) {
				throw new IOException("[" + note.getTitle() + "] exists, please change");
			}
			if (exists.getLink().equals(note.getLink())) {
				throw new IOException("[" + note.getLink() + "] exists, please change");
			}
			if (exists.getFile().equals(note.getFile())) {
				throw new IOException("[" + note.getFile() + "] exists, please change");
			}
		}
	}

	private static String getCurrentDate() {
		SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
		return format.format(new Date());
	}

	private static String getCurrentPath(String filename, boolean isAbs) throws IOException {
		SimpleDateFormat format = new SimpleDateFormat("/yyyy/MM/");
		String docsFolder = Props.getProperties(META_PROPERTIES, "site_docs");
		String docsRoot = isAbs ? IO.transferToPath(IO.USER_DIR + "/" + docsFolder) : docsFolder;
		return docsRoot + format.format(new Date()) + filename;
	}

	private static CommandLine parseCmd(String[] args) throws Exception {
		Option option_p = new Option(CMD_POST, "post");
		option_p.setArgs(0);
		Option option_t = new Option(CMD_TITLE, "title");
		option_t.setArgs(1);
		Option option_l = new Option(CMD_LINK, "link");
		option_l.setArgs(1);
		Option option_r = new Option(CMD_REMOVE, "remove");
		option_r.setArgs(0);
		Option option_b = new Option(CMD_BUILD, "build");
		option_b.setArgs(0);

		Options options = new Options();
		options.addOption(option_p);
		options.addOption(option_t);
		options.addOption(option_l);
		options.addOption(option_r);
		options.addOption(option_b);
		CommandLineParser parser = new BasicParser();
		return parser.parse(options, args);
	}

	private static List<Note> readNotes() throws IOException {
		File docs = IO.openFile(IO.USER_DIR + "/" + Props.getProperties(META_PROPERTIES, "site_docs_txt"));
		String docsFile = FileUtils.readFileToString(docs, IO.UTF_8);
		List<Note> notes = JSONArray.parseArray(docsFile, Note.class);
		return notes;
	}

	private static void tip(Object message) {
		System.out.println(String.valueOf(message));
	}

	private static void writeNotes(List<Note> notes) throws IOException {
		File docs = IO.openFile(IO.USER_DIR + "/" + Props.getProperties(META_PROPERTIES, "site_docs_txt"));
		FileUtils.write(docs, JSONArray.toJSONString(notes), IO.UTF_8);
	}

	public static void main(String[] args) throws IOException {
		_cmd(args);
	}
}